// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#pragma once

#include <memory>
#include <string>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/huobi_futures/api_util/auth_key.h"
#include "coin2/exchange/order/huobi.pb.h"

namespace coin2::exchange::huobi::api_order {

enum HuobiOrderSubTopicId : int { REST_DEPOSIT = 10000, REST_WITHDRAWAL = 10001 };

}  // namespace coin2::exchange::huobi::api_order

class HuobiNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::HuobiRestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using HuobiOrderSubTopicId = coin2::exchange::huobi::api_order::HuobiOrderSubTopicId;
  using AsioHttpContextList = std::list<std::shared_ptr<AsioHttpContext>>;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);

 public:
  explicit HuobiNativePrivateClient(const NativeClientConfig& config);

  std::shared_ptr<AsioHttpContext> QueryAccounts();
  std::shared_ptr<AsioHttpContext> QueryAccountBalance();
  std::shared_ptr<AsioHttpContext> QueryMarginCrossedAccountBalance();
  std::shared_ptr<AsioHttpContext> QueryMarginIsolatedAccountBalance();
  std::shared_ptr<AsioHttpContext> QueryDepositWithdraw(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QuerySingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOpenOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryHistoryOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOrderMatchResults(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QuerySingleOrderMatchResults(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryDeposit();
  std::shared_ptr<AsioHttpContext> QueryWithdrawal();
  std::shared_ptr<AsioHttpContext> PlaceSingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceBatchOrders(const std::vector<RestParams>& params);
  std::shared_ptr<AsioHttpContext> CancelOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> BatchCancelOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> BatchCancelOpenOrders(const RestParams& params);

  std::shared_ptr<AsioHttpContext> QueryTransfers(const RestParams& params);

  AsioHttpContextList SubmitRestQueryList(const RestQueryProto& query);

  void SetAccountId(const std::string& channel, void* data) {
    account_id_ = *(static_cast<std::string*>(data));
  }

  void SetAccountIdTypeMap(const std::string& channel, void* data) {
    account_type_map_ = *(static_cast<std::map<std::string, std::string>*>(data));
    account_id_ = account_type_map_["spot"];
    margin_isolated_account_id_ = account_type_map_["margin"];
    margin_crossed_account_id_ = account_type_map_["super-margin"];
  }

  std::map<std::string, std::string>& GetAccountIdTypeMap() { return account_type_map_; };

  bool has_account_id() const { return !account_id_.empty(); }
  bool has_margin_crossed_account_id() const { return !margin_crossed_account_id_.empty(); }
  bool has_margin_isolated_account_id() const { return !margin_isolated_account_id_.empty(); }
  bool has_account_id_type() const { return !(account_type_map_.size() == 0); }

  const std::string& account_id() const { return account_id_; }
  const std::string& margin_crossed_account_id() const { return margin_crossed_account_id_; }
  const std::string& margin_isolated_account_id() const { return margin_isolated_account_id_; }

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);

 protected:
  std::string account_id_;
  std::string margin_crossed_account_id_;
  std::string margin_isolated_account_id_;
  std::map<std::string, std::string> account_type_map_;  // "type": "super-margin",  "id": 17828968
};
